(*
  HDFS Digital Logic Hardware Design Utility Library (hdfslib.dll)
  Copyright (C) 2006 Andy Ray.

  This library is free software; you can redistribute it and/or
  modify it under the terms of the GNU Lesser General Public
  License as published by the Free Software Foundation; either
  version 2.1 of the License, or (at your option) any later version.

  This library is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  Lesser General Public License for more details.

  You should have received a copy of the GNU Lesser General Public
  License along with this library; if not, write to the Free Software
  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
*)

open DigitalLogic
open Numeric.Ops
open Signal
open List

let test_behave() = 
  let c0 = input "c0" 2 in
  let c1 = input "c1" 1 in
  let c2 = input "c2" 1 in
  let c2 = constb "0" in

  let s0 = input "s0" 2 in
  let s1 = input "s1" 2 in
  let s2 = input "s2" 2 in
  let s3 = input "s3" 2 in
  let s = [s0;s1;s2;s3] in

  let w0 = (b_wire0 2) -- "wire0" in
  let w1 = (b_wire0 2) -- "wire1" in
  let w2 = (b_wire0 2) -- "wire2" in
  let w3 = (b_wire0 2) -- "wire3" in
  let w = [w0;w1;w2;w3] in

  (* Generate some behavioural circuits.  Note we reuse signals on the left of $==.  
     This isnt really allowed.  if converted the later $== assignments to these wires will fail *)

  let test0 = [
    b_if (c0) [ 
      w0 $== s0;
    ] []
  ] in
    
  let test1 = [
    w3 $== s0;
    b_switch (c0) [
      b_case (consti 2 (-2)) [ w1 $== s0; ];
      b_case (consti 2 (-1)) [ w1 $== s1; ];
      b_case (consti 2   0)  [ w1 $== s2; ];
      b_case (consti 2   1)  [ w1 $== s3; ];
    ];
    b_switch (c0) [
      b_case (consti 2 0) [ w2 $== s0; b_if c0 [ w3 $== s1; ] []; ];
      b_case (consti 2 1) [ w2 $== s1; ];
      b_case (consti 2 2) [ w2 $== s2; ];
      b_case (consti 2 3) [ w2 $== s3; ];
    ];
  ] in

  let test2 = [
    w0 $== s0;
    w1 $== s1;
    b_if (c0) [
      w0 $== s0;
      w1 $== s1; (* aggressive mode should remove this *)
      b_if (c1) [ 
        w0 $== s3; (* this is removed *)
        w1 $== s2;
      ] [
        w1 $== s3;
        b_switch (c0) 
          (map (fun i -> b_case (consti 2 i) [ (nth w i) $== (nth s i); ]) [0; 1; 2; 3])
      ];
    ] [];
  ] in

  let r0 = b_regc enable 4 -- "b_reg0" in
  let r1 = b_regc enable 4 -- "b_reg1"  in
  let test3 = [
    //r1.[2,2] $== s1 ++ s1;
    r1 $== s1 ++ s1;
    b_if (c0) [
      r0 $== s0 ++ s1;
    ] [
      //r1.[3,0] $== s1 ++ s1;
      r1 $== s1 ++ s1;
    ]
  ] in

  (* compile *)
  behave test3;
  //let outputs = map (fun (n,s) -> output n s) [ ("w1",w1.q); ("w2",w2.q); ("w3",w3.q) ] in
  let outputs = map (fun (n,s) -> output n s) [ ("w1",r0.q); ("w2",r1.q) ] in
  let circuit = Circuit.create outputs in
  
  Resources.report stdout circuit;
  Circuit.write_file Vhdl.write "output/" "test_behave" ".vhd" circuit;
  Circuit.write_file Verilog.write "output/" "test_behave" ".v" circuit;
  Circuit.write_file Fsharp.write "output/" "test_behave" ".fs" circuit

let _ = test_behave()
